<?php
namespace app\common\service\lib\kdzs;


use think\Exception;
use think\facade\Log;

class KdzsClient
{
    /**
     * 分配给应用的AppKey
     */
	private $appkey;

    /**
     * 分配给应用的AppSecret
     */
	private $appSecret;

    /**
     * 正式环境
     */
    private $gatewayUrl = "https://gw.kuaidizs.cn/router";

    /**
     * 响应格式。默认为json格式，可选值：json
     */
    private $format = "json";

    /**
     * API协议版本 可选值：1.0
     */
    private $version = "1.0";

    /**
     * 签名的摘要算法(默认 md5)，可选值为：md5
     */
    private $signMethod = "md5";

    /**
     * 请求读取超时时间
     */
    public $readTimeout;

    /**
     * 连接超时时间
     */
    public $connectTimeout;

    /**
     * 请求前是否校验字段
     */
    public $checkRequest=true;

    private $sdkVersion = "kdzs-sdk-php-20210825";

	public function __construct($appkey = "", $appSecret = ""){
		$this->appkey = $appkey;
		$this->appSecret = $appSecret;
	}

	protected function generateSign($params)
	{
		ksort($params);

		$stringToBeSigned = $this->appSecret;
		foreach ($params as $k => $v)
		{
			if(is_string($v) && "@" != substr($v, 0, 1) || is_numeric($v))
			{
				$stringToBeSigned .= "$k$v";
			}
		}
		unset($k, $v);
		$stringToBeSigned .= $this->appSecret;
		return strtoupper(md5($stringToBeSigned));
	}

	public function curl($url, $postFields = null)
	{
		$ch = curl_init();
		curl_setopt($ch, CURLOPT_URL, $url);
		curl_setopt($ch, CURLOPT_FAILONERROR, false);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
		if ($this->readTimeout) {
			curl_setopt($ch, CURLOPT_TIMEOUT, $this->readTimeout);
		}
		if ($this->connectTimeout) {
			curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $this->connectTimeout);
		}
		curl_setopt ( $ch, CURLOPT_USERAGENT, "top-sdk-php" );
		//https 请求
		if(strlen($url) > 5 && strtolower(substr($url,0,5)) == "https" ) {
			curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
			curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
		}

		if (is_array($postFields) && 0 < count($postFields))
		{
			$postBodyString = "";
			foreach ($postFields as $k => $v)
			{
				if(!is_string($v) && !is_numeric($v))
					continue ;
                //判断是不是文件上传
				if("@" != substr($v, 0, 1) && is_string($v) || is_numeric($v))
				{
					$postBodyString .= "$k=" . urlencode($v) . "&"; 
				}
				else//文件上传用multipart/form-data，否则用www-form-urlencoded
				{
				    //不支持文件
                    throw new \Exception("暂不支持文件上传！");
				}
			}
			unset($k, $v);
			curl_setopt($ch, CURLOPT_POST, true);
            $header = array("content-type: application/x-www-form-urlencoded; charset=UTF-8");
            curl_setopt($ch,CURLOPT_HTTPHEADER,$header);
            curl_setopt($ch, CURLOPT_POSTFIELDS, substr($postBodyString,0,-1));
//            echo $postBodyString."\n";
		}
		$reponse = curl_exec($ch);
		
		if (curl_errno($ch))
		{
			throw new \Exception(curl_error($ch),0);
		}
		else
		{
			$httpStatusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
			if (200 !== $httpStatusCode)
			{
				throw new \Exception($reponse,$httpStatusCode);
			}
		}
		curl_close($ch);
		return $reponse;
	}

    /**
     * Author:Yingbo Sun
     * 验证参数 发送请求
     * @param $request
     * @param null $session
     * @return ResultSet|mixed
     * @throws \Exception
     */
	public function execute($request, $session = null)
	{
		$result =  new ResultSet();
		//判断请求前是否验证
		if($this->checkRequest) {
			try {
				$request->check();
			} catch (\Exception $e) {
			    $result->success = false;
				$result->code = $e->getCode();
				$result->msg = $e->getMessage();
				return $result;
			}
		}
        //获取请求参数
        $apiParams = $request->getApiParas();
        //检查文件表单
        foreach ($apiParams as $key => $value) {
            if(is_array($value) && array_key_exists('type',$value) && array_key_exists('content',$value) ){
                throw new \Exception("暂不支持文件上传！");
            }
        }
		//组装系统参数
        $sysParams["method"] = $request->getApiMethodName();
		$sysParams["appKey"] = $this->appkey;
        $sysParams["timestamp"] =$this->getTimestamp();
        $sysParams["format"] = $this->format;
		$sysParams["version"] = $this->version;
		$sysParams["sign_method"] = $this->signMethod;
		if (null != $session)
		{
			$sysParams["session"] = $session;
		}
		//签名
		$sysParams["sign"] = $this->generateSign(array_merge($apiParams, $sysParams));

		//发起HTTP请求
		try
		{
            $resp = $this->curl($this->gatewayUrl, array_merge($apiParams, $sysParams));
		}
		catch (\Exception $e)
		{
//			Kohana::$log->add(Log::ERROR, Kohana_Exception::text($e));
            $result->success = false;
			$result->code = $e->getCode();
			$result->msg = $e->getMessage();
			return $result;
		}

		unset($apiParams);
		unset($fileFields);

		//解析返回结果
		if ("json" == $this->format)
		{
			$respObject = json_decode($resp);
//			dd($respObject);
			if ($respObject->trace_id){
			    $respObject->traceId = $respObject->trace_id;
                unset($respObject->trace_id);
            }
		}
		else
		{
			throw new \Exception("不支持的format=".$this->format);
		}
		return $respObject;
	}

	private function getTimestamp(){
        $timestamp = time();
        $dt = new \DateTime("now", new \DateTimeZone('asia/shanghai'));
        $dt->setTimestamp($timestamp);
        return $dt->format("Y-m-d H:i:s");
    }

}
